package be.rivendale.renderer.mk2.local;

import be.rivendale.geometry.AxisAlignedBoundingBox;
import be.rivendale.geometry.Camera;
import be.rivendale.ghetto.Shader;
import be.rivendale.material.Color;
import be.rivendale.mathematics.Ray;
import be.rivendale.mathematics.Triangle;
import be.rivendale.mathematics.intersection.Intersection;
import be.rivendale.mathematics.intersection.RayIntersectionMode;
import be.rivendale.renderer.mk2.data.Queue;
import be.rivendale.renderer.mk2.data.Rectangle;
import be.rivendale.renderer.mk2.data.RenderContext;
import be.rivendale.renderer.mk2.data.Segment;

public class RenderThread extends Thread {
    private Queue<Rectangle> inputQueue;
    private Queue<Segment> outputQueue;
    private Color baseColor;
    private int slowness;

    public RenderThread(Queue<Rectangle> inputQueue, Queue<Segment> outputQueue, Color baseColor, int slowness) {
        super(RenderThread.class.getSimpleName());
        this.inputQueue = inputQueue;
        this.outputQueue = outputQueue;
        this.baseColor = baseColor;
        this.slowness = slowness;
    }

    @Override
    public void run() {
        System.out.println("Rendering thread started.");
        while(true) {
            Rectangle rectangle = inputQueue.take();
            Segment segment = new Segment(rectangle);
            for (int y = 0; y < rectangle.getHeight(); y += 1) {
                for (int x = 0; x < rectangle.getWidth(); x += 1) {
                    Color color = samplePixel(rectangle.getX() + x, rectangle.getY() + y);
                    segment.plot(x, y, color.add(baseColor));
                }
            }
            outputQueue.put(segment);
            sleep();
        }
    }

    private void sleep() {
        try {
            Thread.sleep(slowness);
        } catch (InterruptedException exception) {
            throw new RuntimeException("Unable to sleep", exception);
        }
    }

    private Color samplePixel(int x, int y) {
        RenderContext renderContext = RenderContext.getInstance();
        Ray ray = getCamera().castRay(x, y, renderContext.getRenderInformation().getHorizontalCameraResolution(), renderContext.getRenderInformation().getVerticalCameraResolution());
        AxisAlignedBoundingBox boundingBox = renderContext.getRenderInformation().getScene().getModel().getAxisAlignedBoundingBox();
        if (boundingBox.intersection(ray) == null) {
            return new Color(0, 1.0/4, 1.0/2);
        }
        for (Triangle triangle : renderContext.getRenderInformation().getScene().getModel().getTriangles()) {
            Intersection intersection = triangle.intersection(ray, RayIntersectionMode.afterPassThroughPoint);
            if(intersection.doesIntersect()) {
                return Shader.shade(renderContext.getRenderInformation().getScene().getLight(), triangle.normal().normalize().invert(), Color.RED, intersection.getIntersectionPoint());
            }
        }
        return new Color(0, 1.0/4, 1.0/2).multiply(0.75);
    }

    protected Camera getCamera() {
        return RenderContext.getInstance().getRenderInformation().getScene().getCamera();
    }

}
